package com.hongxin.nw.netty.handle;

import com.alibaba.fastjson.JSONObject;
import com.hongxin.nw.netty.config.ApplicationContextProvider;
import com.hongxin.nw.netty.context.ChannelContext;
import com.hongxin.nw.netty.context.StartState;
import com.hongxin.nw.netty.context.StopState;
import com.hongxin.nw.netty.factory.AnalysisFactory;
import com.hongxin.nw.netty.factory.AnswerFactory;
import com.hongxin.nw.netty.factory.MqFactory;
import com.hongxin.nw.netty.model.Transfer;
import com.hongxin.nw.netty.model.analysis.ASDUstart;
import com.hongxin.nw.netty.server.AuthService;
import com.hongxin.nw.netty.utils.BinaryTools;
import com.hongxin.nw.netty.utils.JSONUtils;
import com.hongxin.nw.netty.utils.MyJson;
import com.hongxin.nw.netty.utils.pools.AsduStartPools;
import com.hongxin.nw.netty.utils.pools.CodePools;
import com.hongxin.nw.netty.utils.pools.CodeTypePools;
import com.hongxin.nw.netty.utils.pools.HeartBeatPools;
import com.hongxin.nw.netty.values.StaticValue;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 业务处理
 * @author guoxiaolin
 * @date 创建于 上午9:14 2019/5/10
 */
@Slf4j
public class InitHandler  extends ByteToMessageCodec<Object>{

    /**
     * 客户端去和服务端连接成功时触发
     * @param ctx 通道
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("**************** 通道连接成功 切割线 ****************");
    }

    /**
     * 读取消息
     * @param ctx 通道
     * @param msg 数据
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
        AuthService authService = ApplicationContextProvider.getBean(AuthService.class);
        ByteBuf bb = (ByteBuf)msg;
        bb.retain();
        String startByte = BinaryTools.subByteBuf(4,0, bb);
        if(startByte.equals(StaticValue.LOGIN_IDENTIFY)){
            ASDUstart asdUstart = new ASDUstart();
            asdUstart.analysisStr(bb);
            log.info("设备请求连接:{}",asdUstart.toString());
            MyJson data = authService.signIn(asdUstart.getCode());
            if (data.getCode() == StaticValue.SUCCESS){//业务系统签到成功
                CodePools.addCode(ctx.channel().id().asShortText(), asdUstart.getCode());//通道ID与设备编号的对应关系
                CodeTypePools.addCodeType(asdUstart.getCode(), data.getIntData());//设备编号与设备类型对应关系(1:直流/2:交流)
                AsduStartPools.addAsduStart(asdUstart.getCode(),asdUstart);//设备编号与启动协议帧数据(asdu)
                ctx.channel().writeAndFlush(msg);
            }
        }else{
            //记录设备最新请求时间
            HeartBeatPools.addHB(ctx.channel().id().asShortText(), System.currentTimeMillis()/1000);//设备编号与心跳时间
            String code = CodePools.getCode(ctx.channel().id().asShortText());
            Transfer transfer = AnalysisFactory.getInstance().analysisData(code, bb);//解析
            JSONObject sendJson = MqFactory.getInstance().sendData(transfer);//发送MQ
            JSONObject answerJson = AnswerFactory.getInstance().answerConfirm(transfer);//应答设备
            bb.release();
            log.info("record记录:{}, eType(交流1/直流2):{}",transfer.getRecord(), transfer.getEType());
            log.info("设备:{}, 解析ASDU:{}, 解析数据:{}", code, transfer.getAsdu(), transfer.getObj());
            log.info("设备:{}, 信息:{}, 发送数据:{}", code, sendJson.getString(JSONUtils.JSON_MSG), sendJson.getString(JSONUtils.JSON_DATA));
            log.info("设备:{}, 信息:{}, 应答数据:{}", code, answerJson.getString(JSONUtils.JSON_MSG), answerJson.getString(JSONUtils.JSON_DATA));
        }
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception{
        ChannelFuture cf;
        try {
            cf = ctx.writeAndFlush(msg).sync().addListener((ChannelFutureListener) channelFuture -> {});
            if (cf.isSuccess()){
                ChannelContext context = new ChannelContext();
                context.setCtx(ctx);
                context.setState(new StartState());
                context.getState().doAction(context);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设备断开
     * @param ctx 通道
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception{
        ChannelContext context = new ChannelContext();
        context.setCtx(ctx);
        context.setState(new StopState());
        context.getState().doAction(context);
    }

    /**
     * 读操作时捕获到异常时调用
     * @param ctx 通道
     * @param cause 异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.info("************************************************************");
        log.info("** 异常 {}", cause.getMessage());
        log.info("************************************************************");
        cause.printStackTrace();
    }
    /**
     * 通知处理器最后的channelRead()是当前批处理中的最后一条消息时调用
     * eventLoop被到来的数据唤醒后read数据并包装成msg,然后将msg作为参数调用channelRead方法，
     * 期间做个判断，read到0个字节或者是read到的字节数小于buffer的容量，满足以上条件就会调用channelReadComplete方法。
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx){
        log.info("**************  报文处理完毕  分割线  **************\n");
        ctx.flush();
    }
    @Override
    protected void encode(ChannelHandlerContext ctx, Object o, ByteBuf byteBuf){}
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list){}
}


